package com.net.xpay.core.validator;

import com.beust.jcommander.internal.Lists;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.net.xpay.common.domain.CheckCode;
import com.net.xpay.common.domain.User;
import com.net.xpay.common.domain.UserProfile;
import com.net.xpay.common.enums.config.CommonSysConfigKey;
import com.net.xpay.common.enums.user.CheckCodeType;
import com.net.xpay.common.helper.CommonSysConfigHelper;
import com.net.xpay.common.helper.RedisHelper;
import com.net.xpay.common.manager.CheckCodeManager;
import com.net.xpay.common.manager.UserProfileManager;
import com.net.xpay.common.util.GoogleAuthUtil;
import com.net.xpay.core.constant.RedisKey;
import com.net.common.exception.BusinessException;
import com.net.common.util.LocalDateUtil;
import com.net.common.util.SerializationUtil;
import com.net.common.util.StreamUtil;
import com.net.xpay.alipay.enums.IdentityType;
import com.net.xpay.alipay.safePay.PoseidonSafePayAlipayClient;
import com.net.xpay.common.validator.CheckCodeValidator;
import com.net.xpay.core.constant.PoseidonErrorCode;
import com.net.xpay.core.domain.safePay.SafePayBatch;
import com.net.xpay.core.domain.safePay.SafePayBookAccount;
import com.net.xpay.core.enums.PayeeType;
import com.net.xpay.core.manager.safePay.SafePayBatchManager;
import com.net.xpay.core.manager.safePay.SafePayBookAccountManager;
import com.net.xpay.core.model.SafePayBatchCreateModel;
import com.net.xpay.core.model.SafePayBatchTransModel;
import com.net.xpay.core.model.SafePayTransModel;
import com.net.xpay.core.utils.BankUtil;
import com.net.xpay.core.utils.MoneyCheckUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

/**
 * 安全付批次参数验证
 */
@Slf4j
@Component
public class SafePayBatchValidator {
    //外部批次号最大长度
    private static final int IMPORT_BATCH_NO_MAX_LENGTH = 64;
    //订单备注最大长度
    private static final int ORDER_REMARK_MAX_LENGTH = 32;
    //转账最多个数
    private static final int ORDER_MAX_SIZE = 2000;

    //单笔转账最大金额
    private static final String ORDER_MAX_MONEY = "50000";

    //单笔转账最小金额
    private static final String ORDER_MIN_MONEY = "0.1";

    @Autowired
    private SafePayBatchManager safePayBatchManager;

    @Autowired
    private SafePayBookAccountManager safePayBookAccountManager;

    @Autowired
    private PoseidonSafePayAlipayClient xpaySafePayAlipayClient;

    @Autowired
    private CheckCodeValidator checkCodeValidator;

    @Autowired
    private CheckCodeManager checkCodeManager;

    @Autowired
    private UserProfileManager userProfileManager;

    @Autowired
    private RedisHelper redisHelper;

    @Autowired
    private CommonSysConfigHelper commonSysConfigHelper;

    public void validateCreateBatch(User user, SafePayBatchCreateModel model) {
        log.info("validateCreateBatch userId={}|params={}", user.getId(), SerializationUtil.obj2String(model));
        if (!PayeeType.isValid(model.getType())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "收款类型错误,请传入正确的类型（ 1.支付宝 2.银行卡）");
        }

        if (PayeeType.BANK.equals(model.getType())) {
            Long openSafePayBank = commonSysConfigHelper.getLong(CommonSysConfigKey.OPEN_SAFE_PAY_BANK);
            openSafePayBank = openSafePayBank == null ? 0L : openSafePayBank;
            if (openSafePayBank == 0L) {
                throw new BusinessException(PoseidonErrorCode.SYSTEM_PRESERVE, "系统侧调整，请先下发到户，到卡明日再试");
            }
            UserProfile userProfile = userProfileManager.getById(user.getId());
            if (Boolean.FALSE.equals(userProfile.getOpenSafePayBank()) || userProfile.getOpenSafePayBank() == null ){
                throw new BusinessException(PoseidonErrorCode.SYSTEM_PRESERVE, "到卡业务升级中，暂停使用");
            }
        }

        UserProfile userProfile = userProfileManager.getById(user.getId());
        if (!Boolean.TRUE.equals(userProfile.getOpenSafePay())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "尚未开通安全付功能");
        }

        if (Strings.isNullOrEmpty(model.getAlipayNickName())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请输入支付宝账号");
        }

        if (Strings.isNullOrEmpty(model.getImportBatchNo())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "外部批次号不能为空");
        }
        if (model.getImportBatchNo().length() > IMPORT_BATCH_NO_MAX_LENGTH) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "外部批次号不能超过" + IMPORT_BATCH_NO_MAX_LENGTH + "个字");
        }

        if (CollectionUtils.isEmpty(model.getPayTrans())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "至少有一个收款明细");
        }

        if (model.getTotalCount() == null) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "批次总笔数不能为空");
        }

        if (model.getPayTrans().size() != model.getTotalCount()) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "批次总笔数不匹配");
        }

        if (model.getPayTrans().size() > ORDER_MAX_SIZE) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "一批次最多" + ORDER_MAX_SIZE + "个收款人");
        }

        if (Strings.isNullOrEmpty(model.getTotalTransAmount())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "批次总金额不能为空");
        }

        if (!MoneyCheckUtil.isValidMoney(model.getTotalTransAmount(), 2)) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "批次总金额格式错误，单位为元，最多2位小数");
        }

        if (!Strings.isNullOrEmpty(model.getNotifyUrl())) {
            if (model.getNotifyUrl().length() > 255) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "推送地址长度不能超过255");
            }
            if (!model.getNotifyUrl().contains("http://") && !model.getNotifyUrl().contains("https://")) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "推送地址协议错误，请使用http://或者https://协议");
            }
            model.setNotifyUrl(model.getNotifyUrl().trim());
        }

        SafePayBatch batch = safePayBatchManager.findByImportBatchNo(user.getId(), model.getImportBatchNo());
        if (batch != null) {
            throw new BusinessException(PoseidonErrorCode.IMPORT_BATCH_NO_USED, "外部批次号已被使用");
        }

        List<String> importBizNos = new ArrayList<>();
        for (SafePayTransModel order : model.getPayTrans()) {
            if (Strings.isNullOrEmpty(order.getImportBizNo())) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "商户明细订单不能空");
            }
            if (order.getImportBizNo().length() > 32) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "商户明细订单不能超过32位");
            }
            if (importBizNos.contains(order.getImportBizNo())) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "商户明细订单重复：" + order.getImportBizNo());
            }
            if (!MoneyCheckUtil.isValidMoney(order.getTransAmount(), 2)) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "转账金额格式错误，最多2位小数");
            }
            if (new BigDecimal(order.getTransAmount()).compareTo(new BigDecimal(ORDER_MAX_MONEY)) > 0) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "单笔收款不能超过" + ORDER_MAX_MONEY + "元");
            }
            if (new BigDecimal(order.getTransAmount()).compareTo(new BigDecimal(ORDER_MIN_MONEY)) < 0) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "单笔收款不能小于" + ORDER_MIN_MONEY + "元");
            }

            List<String> whiteOrderTitleList = Lists.newArrayList("酬劳发放", "福利发放", "佣金结算", "用户提现", "推广佣金", "费用报销", "货款结算");

            if (!Strings.isNullOrEmpty(order.getOrderTitle())) {
                if (!whiteOrderTitleList.contains(order.getOrderTitle())) {
                    throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "转账业务标题仅可选：" + Joiner.on(",").join(whiteOrderTitleList));
                }
            }

            if (!Strings.isNullOrEmpty(order.getRemark()) && order.getRemark().length() > ORDER_REMARK_MAX_LENGTH) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "转账备注不能超过" + ORDER_REMARK_MAX_LENGTH + "个字");
            }

            if (Strings.isNullOrEmpty(order.getIdentity())) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "收款支付宝账号不能为空");
            }
            if (order.getIdentity().contains(" ")) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "收款支付宝账号不能包含空格");
            }

            if (PayeeType.BANK.equals(model.getType())) {
                if (!BankUtil.isValid(order.getIdentity())) {
                    throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "收款银行卡号格式错误：" + order.getIdentity());
                }
                if (Strings.isNullOrEmpty(order.getName())) {
                    throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "收款人姓名不能为空");
                }
            } else {
                if (IdentityType.BANKCARD_ACCOUNT.getValue().equals(order.getIdentityType())) {
                    log.info("validateCreateBatch identityType error|userId={}|identityType={}", user.getId(), order.getIdentityType());
                    throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "收款账号类型错误:identityType为银行卡类型，type请传2");
                }
                if (!IdentityType.ALIPAY_USER_ID.getValue().equals(order.getIdentityType()) && !IdentityType.EMPLOYEE_ACCOUNT_ID.getValue().equals(order.getIdentityType())) {
//                    if (!AlipayAccountCheckUtil.isEffectiveAccount(order.getIdentity())) {
//                        log.info("validateCreateBatch identify no valid|userId={}|identify={}", user.getId(), order.getIdentity());
//                        throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "收款人支付宝账号格式错误：" + order.getIdentity());
//                    }
                    if (Strings.isNullOrEmpty(order.getName())) {
                        throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "收款人姓名不能为空");
                    }
                }
            }

            importBizNos.add(order.getImportBizNo());
        }

        BigDecimal totalTransAmount = StreamUtil.sum(model.getPayTrans(), (Function<SafePayTransModel, BigDecimal>) safePayTransModel -> new BigDecimal(safePayTransModel.getTransAmount()));
        if (totalTransAmount.compareTo(new BigDecimal(model.getTotalTransAmount())) != 0) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "批次总金额不匹配");
        }


        SafePayBookAccount safePayBookAccount = safePayBookAccountManager.findByAlipayNickName(user.getId(), model.getAlipayNickName());
        if (safePayBookAccount == null) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "账号不存在或未签约");
        }
        //限额
        checkLimitTransAmount(user, safePayBookAccount, totalTransAmount);
    }

    private void checkLimitTransAmount(User user, SafePayBookAccount safePayBookAccount, BigDecimal totalTransAmount) {
        UserProfile userProfile = userProfileManager.getById(user.getId());
        if (userProfile.getSafePayTransAmountDayLimit() == null) {
            return;
        }

        LocalDateTime day = LocalDateTime.now();
        // 根据当前时间获取改天的起始时间和结束时间
        LocalDateTime currentDayStartTime = LocalDateUtil.getDayStart(day);
        LocalDateTime currentDayEndTime = LocalDateUtil.getDayEnd(day);
        // 进行查询
        BigDecimal currentDayLimit = safePayBatchManager.getTransferLimit(currentDayStartTime, currentDayEndTime, safePayBookAccount.getUserId(), safePayBookAccount.getId());
        BigDecimal leftLimit = userProfile.getSafePayTransAmountDayLimit().subtract(currentDayLimit);
        if (leftLimit.compareTo(totalTransAmount) < 0) {
            throw new BusinessException(PoseidonErrorCode.ALIPAY_DAY_LIMIT, "付款支付宝账号（" + safePayBookAccount.getAlipayNickName() + "）日限额不足，当日剩余额度" + leftLimit + "元，当前批次转账金额为" + totalTransAmount + "元，超过日限无法支付！");
        }
    }

    public SafePayBatch validateTransSafePayBatch(User user, SafePayBatchTransModel model) {
        log.info("validateTransSafePayBatch userId={}|params={}", user.getId(), SerializationUtil.obj2String(model));
        SafePayBatch batch = safePayBatchManager.findByImportBatchNo(user.getId(), model.getImportBatchNo());
        if (batch == null) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "批次不存在");
        }

        Long openSafePayBank = commonSysConfigHelper.getLong(CommonSysConfigKey.OPEN_SAFE_PAY_BANK);
        openSafePayBank = openSafePayBank == null ? 0L : openSafePayBank;
        if (PayeeType.BANK.equals(batch.getType())) {
            if (openSafePayBank == 0L) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "到卡业务升级中，暂停使用");
            }
            UserProfile userProfileById = userProfileManager.getById(user.getId());
            if (Boolean.FALSE.equals(userProfileById.getOpenSafePayBank()) || userProfileById.getOpenSafePayBank() == null ){
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "到卡业务升级中，暂停使用");
            }
        }

        if (Strings.isNullOrEmpty(model.getImportBatchNo())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "外部批次号不能为空");
        }

        SafePayBookAccount account = safePayBookAccountManager.findById(batch.getUserId(), batch.getSafePayBookAccountId());

        //日限额
        checkLimitTransAmount(user, account, batch.getTotalTransAmount());

        //是否需要短信验证
        if (Boolean.TRUE.equals(batch.getNeedEnsure())) {
            if (model.getAuthMethod() != null && model.getAuthMethod() == 1) {
                Object errCount = redisHelper.get(RedisKey.GOOGLE_AUTH_ERROR_COUNT + ":" + user.getId());
                long errNum = 0;
                if (errCount != null) {
                    errNum = Long.parseLong(errCount.toString());
                    if (errNum >= 3L) {
                        throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "谷歌验证码连续输错3次已被禁用，请5分钟后再试");
                    }
                }
                //谷歌验证器验证
                UserProfile userProfile = userProfileManager.getById(user.getId());
                if (!Boolean.TRUE.equals(userProfile.getUseGoogleAuth())) {
                    throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "谷歌验证未开启，无法验证");
                }
                if (Strings.isNullOrEmpty(userProfile.getGoogleAuthKey())) {
                    throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "谷歌验证器尚未绑定账号，无法验证");
                }
                boolean pattern;
                try {
                    pattern = GoogleAuthUtil.isPattern(userProfile.getGoogleAuthKey(), Integer.parseInt(model.getCheckCode()));
                } catch (Exception e) {
                    throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "谷歌验证码错误，请输入6位谷歌数字验证码");
                }
                if (!pattern) {
                    errNum++;
                    redisHelper.set(RedisKey.GOOGLE_AUTH_ERROR_COUNT + ":" + user.getId(), errNum, 60 * 5L);

                    throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "谷歌验证码不正确");
                }

            } else {
                //短信验证
                if (Strings.isNullOrEmpty(model.getCheckCode())) {
                    throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请输入短信验证码");
                }
                String mobile = user.getMobile();
                UserProfile userProfile = userProfileManager.getById(user.getId());
                if (!Strings.isNullOrEmpty(userProfile.getReceiveMobile())) {
                    mobile = userProfile.getReceiveMobile();
                }
                SafePayBookAccount safePayBookAccount = safePayBookAccountManager.findByAlipayNickName(user.getId(), batch.getAlipayNickName());
                if (!Strings.isNullOrEmpty(safePayBookAccount.getReceiveMobile())) {
                    mobile = safePayBookAccount.getReceiveMobile();
                }

                CheckCode checkCode = checkCodeManager.findLastByRelatedId(mobile, CheckCodeType.ENSURE_SAFE_PAY_BATCH, batch.getId());
                //验证码不存在，可能是启用了备用手机号验证，查询一下备用手机号验证码
                if (checkCode == null && !Strings.isNullOrEmpty(userProfile.getSpareReceiveMobile())) {
                    checkCode = checkCodeManager.findLastByRelatedId(userProfile.getSpareReceiveMobile(), CheckCodeType.ENSURE_SAFE_PAY_BATCH, batch.getId());
                }
                checkCodeValidator.validateCheckCode(checkCode, model.getCheckCode());
            }

        }

        return batch;
    }
}
